package com.lisp.springframework.core.aop.cglib;

import java.lang.reflect.Method;
import java.util.Date;

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.FixedValue;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;

// https://dzone.com/articles/cglib-missing-manual
// http://jnb.ociweb.com/jnb/jnbNov2005.html
public class Cglib {

    public static void main(String[] args) {
        testCreateProxy();
        System.out.println("--------------------------------");
        testCallbackFilter();
        System.out.println("--------------------------------");
        testMethodInterceptor();
    }
    
    public static void testMethodInterceptor() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        enhancer.setCallback(new MethodInterceptor() {
            
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if(!method.getName().equals("toString")) { // 避免递归调用
                    System.out.println("object=" + obj);
                }
                System.out.println(String.format("method=%s, args=%s", method, args));
                return methodProxy.invokeSuper(obj, args);
            }
        });
        Object proxy = enhancer.create();
        System.out.println(proxy);
        System.out.println(((MyClass)proxy).getName());
    }
    
    public static void testCreateProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Date.class);
        enhancer.setCallback(NoOp.INSTANCE);
        Object proxy = enhancer.create();
        System.out.println(proxy);
    }
    
    public static void testCallbackFilter() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        FixedValue fv = new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return "fixed name";
            }
        };
        enhancer.setCallbacks(new Callback[] {fv, NoOp.INSTANCE});
        
        CallbackFilter filter = new CallbackFilter() {
            @Override
            public int accept(Method m) {
                if(m.getDeclaringClass().equals(MyClass.class)
                        && m.getName().equals("getName")) {
                    return 0;
                } else {
                    return 1;
                }
            }
        };
        enhancer.setCallbackFilter(filter);
        MyClass myClass = (MyClass) enhancer.create();
        System.out.println(myClass.getName());
        System.out.println(myClass);
    }
    
    public static class MyClass {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "MyClass [name=" + name + ", age=" + age + "]";
        }
    }
}
